#ifndef UUID_B17916A43A554E7B293E9D8974AEFB68
#define UUID_B17916A43A554E7B293E9D8974AEFB68

#include "range_coder.hpp"

struct ACoder
{
	ACoder(ByteWriter writer)
	: low(0)
	, high(0xffffffff)
	, writer(writer)
	{
	}
	
	uint32 low;
	uint32 high;
	
	//std::vector<unsigned char> buf;
	ByteWriter writer;
	
	void reset()
	{
		low = 0;
		high = 0xffffffff;
		//buf.clear();
	}
	
	/*
	void putbyte(uint32 b)
	{
		buf.push_back(b);
	}*/
	
	void encode(int y, int p)
	{
		uint32 mid = low + ((high-low) >> 12) * p;
		
#if ZEROFIRST
		if (y)
			low = mid+1;
		else
			high = mid;
#else
		if (y)
			high = mid;
		else
			low = mid+1;
#endif
			
		while ((low^high) < (1 << 24))
		{
			//putbyte(high >> 24);
			writer.put(high >> 24);
			low <<= 8;
			high = (high << 8) + 0xff;
		}
	}
	
	void flush()
	{
		writer.put(low >> 24);
	}
};

struct ADecoder
{
	ADecoder(unsigned char* in, unsigned char* end)
	: low(0)
	, high(0xffffffff)
	, in(in)
	, pos(in)
	, end(end)
	{
		init();
	}
	
	uint32 low;
	uint32 x;
	uint32 high;

	unsigned char* in;
	unsigned char* pos;
	unsigned char* end;
	
	unsigned char getbyte()
	{
		return (pos != end ? *pos++ : 0xff);
	}
	
	void init()
	{
		low = 0;
		high = 0xffffffff;
		pos = in;
		for (int i=0; i<4; ++i)
			x = (x << 8) + getbyte();
	}
	
	int decode(int p)
	{
		uint32 mid = low + ((high-low) >> 12) * p;

#if ZEROFIRST
		int y = x > mid;
#else
		int y = x <= mid;
#endif

#if ZEROFIRST
		if (y)
			low = mid+1;
		else
			high = mid;
#else
		if (y)
			high = mid;
		else
			low = mid+1;
#endif
		
		while ((low^high) < (1 << 24))
		{
			low <<= 8;
			high = (high << 8) + 0xff;
			x = (x << 8) + getbyte();
		}

		return y;
	}
};

#endif // UUID_B17916A43A554E7B293E9D8974AEFB68
